﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.Collections;
using System.Security;

namespace Noris.Tools.FrxEditor.Data
{
	#region CollectIdx<T> kolekce dat s dvojitým indexem podle item.Id a item.Key
	/// <summary>
	/// Kolekce dat s dvojitým indexem podle int item.Id a string item.Key.
    /// Hodnota klíče string Key je case-insensitive.
	/// </summary>
	/// <typeparam name="T"></typeparam>
	public class CollectIdx<T> : IEnumerable<T>, IDisposable where T : IIdKey
	{
		#region Konstrukce
        /// <summary>
        /// Konstruktor
        /// </summary>
		public CollectIdx()
		{
			this.DisableKeyLogic = false;
            this.DataId = new DictionaryEvnt<int, T>();
            this.DataKey = new DictionaryEvnt<string, T>();
		}
		/// <summary>
		/// Konstruktor.
		/// Umožní zakázat tvorbu indexu podle string Key, když chceme povolit více shodných Key.
		/// Pak nelze podle Key vyhledávat.
		/// </summary>
		/// <param name="disableKeyLogic">Zákaz indexování podle string Key</param>
		public CollectIdx(bool disableKeyLogic)
		{
			this.DisableKeyLogic = disableKeyLogic;
            this.DataId = new DictionaryEvnt<int, T>();
            if (!disableKeyLogic)
                this.DataKey = new DictionaryEvnt<string, T>();
        }
        /// <summary>
        /// Vizualizace
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return "Collection of types:" + typeof(T).Name + "; ItemCount=" + this.DataId.Count + "; KeyCount=" + (DisableKeyLogic ? "disabled" : this.DataKey.Count.ToString());
        }
		/// <summary>
		/// Zákaz indexování podle string Key. Nastavit lze pouze v konstruktoru.
		/// </summary>
		public bool DisableKeyLogic { get; protected set; }
        /// <summary>
        /// Hlavní Dictionary, obsahuje všechny položky, dle int Id
        /// </summary>
		protected DictionaryEvnt<int, T> DataId { get; private set; }
        /// <summary>
        /// Vedlejší Dictinary, obsahuje pouze ty položky, které mají string Key.
        /// Používá se jen tehdy, pokud není zakázaná Key logika (this.DisableKeyLogic).
        /// </summary>
        protected DictionaryEvnt<string, T> DataKey { get; private set; }
		#endregion
		#region Imitace Dictionary a Listu
		/// <summary>
		/// Počet vět
		/// </summary>
		public int Count { get { return this.DataId.Count; } }
		/// <summary>
		/// Přidá větu
		/// </summary>
		/// <param name="value"></param>
		public void Add(T value)
		{
			this.DataId.Add(value.Id, value);
			string k = FormatThisKey(value.Key);
			if (!String.IsNullOrEmpty(k))
				this.DataKey.Add(k, value);
		}
		/// <summary>
		/// Přidá řadu vět
		/// </summary>
		/// <param name="values"></param>
		public void Add(params T[] values)
		{
			foreach (T value in values)
				this.Add(value);
		}
		/// <summary>
		/// Přidá pole vět
		/// </summary>
		/// <param name="list"></param>
		public void AddRange(IEnumerable<T> list)
		{
			foreach (T value in list)
				this.Add(value);
		}
		/// <summary>
		/// Test, zda kolekce již obsahuje větu (podle klíče Id)
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		public bool ContainsKey(T value)
		{
			return this.DataId.ContainsKey(value.Id);
		}
		/// <summary>
		/// Test, zda kolekce již obsahuje větu (podle klíče Id)
		/// </summary>
		/// <param name="id"></param>
		/// <returns></returns>
		public bool ContainsKey(int id)
		{
			return this.DataId.ContainsKey(id);
		}
		/// <summary>
		/// Test, zda kolekce již obsahuje větu (podle klíče Key)
		/// </summary>
		/// <param name="key"></param>
		/// <returns></returns>
		public bool ContainsKey(string key)
		{
			string k = FormatThisKey(key);
			if (k == null) return false;
			return this.DataKey.ContainsKey(k);
		}
		/// <summary>
		/// Zkusí najít větu podle klíče Id
		/// </summary>
		/// <param name="id"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		public bool TryGetValue(int id, out T value)
		{
			return this.DataId.TryGetValue(id, out value);
		}
		/// <summary>
		/// Zkusí najít větu podle klíče Key
		/// </summary>
		/// <param name="key"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		public bool TryGetValue(string key, out T value)
		{
			string k = FormatThisKey(key);
			if (k == null)
			{
				value = default (T);
				return false;
			}
			return this.DataKey.TryGetValue(k, out value);
		}
		/// <summary>
		/// Vrátí větu podle klíče Id.
		/// Pokud neexistuje, vyhodí chybu.
		/// </summary>
		/// <param name="id"></param>
		/// <returns></returns>
		public T this[int id]
		{
			get { return this.DataId[id]; }
		}
		/// <summary>
		/// Vrátí větu podle klíče Key.
		/// Pokud neexistuje, vyhodí chybu.
		/// </summary>
		/// <param name="key"></param>
		/// <returns></returns>
		public T this[string key]
		{
			get
			{
				string k = FormatThisKey(key);
				if (k == null) return default (T);
				return this.DataKey[k];
			}
		}
		/// <summary>
		/// Odebere větu podle klíče Id
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		public bool Remove(T value)
		{
			return this.Remove(value.Id);
		}
		/// <summary>
		/// Odebere větu podle klíče Id
		/// </summary>
		/// <param name="id"></param>
		/// <returns></returns>
		public bool Remove(int id)
		{
			T value;
			if (this.TryGetValue(id, out value))
			{
				this.DataId.Remove(id);
				if (!String.IsNullOrEmpty(value.Key) && this.DataKey.ContainsKey(value.Key))
					this.DataKey.Remove(value.Key);
				return true;
			}
			return false;
		}
		/// <summary>
		/// Odebere větu podle klíče Key
		/// </summary>
		/// <param name="key"></param>
		/// <returns></returns>
		public bool Remove(string key)
		{
			string k = FormatThisKey(key);
			T value;
			if (!String.IsNullOrEmpty(k) && this.DataKey.TryGetValue(k, out value))
			{
				this.DataKey.Remove(k);
				if (this.DataId.ContainsKey(value.Id))
					this.DataId.Remove(value.Id);
				return true;
			}
			return false;
		}
		/// <summary>
		/// Vyprázdní celou kolekci
		/// </summary>
		public void Clear()
		{
			this.DataId.Clear();
            if (!this.DisableKeyLogic)
    			this.DataKey.Clear();
		}
		#endregion
		#region Přidané funkce
		/// <summary>
		/// Vrátí seznam položek, netříděný (v pořadí přidávání).
		/// Seznam je nově vytvořený objekt, který není závislý na interních datech CollectIdx.
		/// </summary>
		public List<T> List
		{
			get
			{
				List<T> result = new List<T>(this.DataId.Values);
				return result;
			}
		}
		/// <summary>
		/// Vrátí seznam položek, tříděný dle hodnoty Key
		/// </summary>
		public List<T> SortedList
		{
			get
			{
				List<T> result = new List<T>(this.DataId.Values);
				result.Sort(delegate(T a, T b) { return String.Compare(a.Key, b.Key, true); });
				return result;
			}
		}
		/// <summary>
		/// Formátuje klíč (vrací null, anebo key.Trim().ToLower();)
        /// Vrací null, pokud je zakázaná logika Key (DisableKeyLogic je true).
		/// </summary>
		/// <param name="key"></param>
		/// <returns></returns>
		protected string FormatThisKey(string key)
		{
			if (this.DisableKeyLogic) return null;
			if (string.IsNullOrEmpty(key)) return null;
			return key.Trim().ToLower();
		}
		/// <summary>
		/// Formátuje klíč (vrací null, anebo key.Trim().ToLower();)
		/// </summary>
		/// <param name="key"></param>
		/// <returns></returns>
		public static string FormatKey(string key)
		{
			if (string.IsNullOrEmpty(key))
				return null;
			return key.Trim().ToLower();
		}
		#endregion
		#region IEnumerable<T> + IEnumerable Members. Dovolí snadno enumerovat seznamem.
		IEnumerator<T> IEnumerable<T>.GetEnumerator()
		{
			return this.DataId.Values.GetEnumerator();
		}
		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
		{
			return this.DataId.Values.GetEnumerator();
		}
        /// <summary>
        /// Dispose
        /// </summary>
		public void Dispose()
		{
			this.Clear();
		}
		void IDisposable.Dispose()
		{
			this.Dispose();
		}
		#endregion
    }
	#endregion
	#region Interface, který garantuje přítomnost property int Id a string Key.
	/// <summary>
	/// Interface, který garantuje přítomnost property int Id a string Key.
	/// Používá se pro objekty, které mohou být ukládány do dvojindexové kolekce CollectIdx.
	/// </summary>
	public interface IIdKey
	{
        /// <summary>
        /// Numerický klíč
        /// </summary>
		int Id { get; }
        /// <summary>
        /// Stringový klíč
        /// </summary>
		string Key { get; }
	}
	#endregion
	#region DictionaryEvnt která poskytuje eventy při změnách
    /// <summary>
    /// DictionaryEvnt : adaptér na Dictionary.
    /// Poskytuje eventy při změnách.
    /// Obsahuje neviditelnou cache na poslední nalezenou hodnotu - pro urychlení opakovaného hledání téhož klíče.
    /// </summary>
    /// <typeparam name="TKey"></typeparam>
    /// <typeparam name="TValue"></typeparam>
	public class DictionaryEvnt<TKey, TValue> : IEnumerable<TValue>, IEnumerable
    {
        #region Konstrukce
        /// <summary>
        /// Vnitřní úložiště dat
        /// </summary>
        protected Dictionary<TKey, TValue> Dict;
        /// <summary>
        /// Vizualizace
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return "DictionaryEvnt<" + typeof(TKey).GetType().Name + ", " + typeof(TValue).GetType().Name + ">; ItemCount=" + this.Dict.Count.ToString();
        }
        #endregion
        #region Eventy
        /// <summary>
        /// Argumenty pro události
        /// </summary>
        public class DictionaryEventArgs : EventArgs
        {
            /// <summary>
            /// Konstruktor
            /// </summary>
            /// <param name="key"></param>
            /// <param name="value"></param>
            public DictionaryEventArgs(TKey key, TValue value)
            {
                this.KeyValue = new KeyValuePair<TKey, TValue>(key, value);
            }
            /// <summary>
            /// Data, o která se jedná
            /// </summary>
            public KeyValuePair<TKey, TValue> KeyValue { get; protected set; }
            /// <summary>
            /// Eventhandler může zakázat operaci
            /// </summary>
            public bool Cancel { get; set; }
        }
        /// <summary>
        /// Předpis pro metodu, která je event handlerem změn v DictionaryEvnt
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        public delegate void DictionaryEventHandler(object sender, DictionaryEventArgs args);
        /// <summary>
        /// Event volaný před přidáním nové položky. 
        /// Handler může přidání zakázat. Pak se položka tiše nepřidá. 
        /// Pokud je třeba vyvolat výjimku, pak ji musí vyvolat handler.
        /// </summary>
        public event DictionaryEventHandler ItemAddBefore;
        /// <summary>
        /// Event volaný před vrácením nalezené položky. 
        /// Handler může vrácení položky zakázat. Pak se položka nevrátí, jako by se nenašla. V metodě this[] get dojde k výjimce Key not exists. V metodě TryGetValue se vrátí false.
        /// Pokud je třeba vyvolat výjimku, pak ji musí vyvolat handler.
        /// </summary>
        public event DictionaryEventHandler ItemGetBefore;
        /// <summary>
        /// Event volaný před vložením existující položky v metodě this[] set. 
        /// Handler může vložení zakázat. Pak se položka tiše nevloží. 
        /// Pokud je třeba vyvolat výjimku, pak ji musí vyvolat handler.
        /// </summary>
        public event DictionaryEventHandler ItemSetBefore;
        /// <summary>
        /// Event volaný před smazáním existující položky. 
        /// Handler může smazání zakázat. Pak se položka tiše nesmaže. 
        /// Pokud je třeba vyvolat výjimku, pak ji musí vyvolat handler.
        /// </summary>
        public event DictionaryEventHandler ItemRemoveBefore;
        #endregion
        #region Neviditelná cache na LastFind položku
        /// <summary>
        /// Cache: reset (po provedení změny v Dictionary.Key = po metodě Add, Remove, Clear).
        /// </summary>
        protected void LastValueReset()
        {
            this.LastExists = false;
            this.LastKey = default(TKey);
            this.LastFound = false;
            this.LastValue = default(TValue);
        }
        /// <summary>
        /// Cache: data existují, jsou uložena a platná
        /// </summary>
        protected bool LastExists;
        /// <summary>
        /// Cache: Klíč posledně hledané položky. Informace o tom, zda byla nalezena je v this.LastFind, nalezená hodnota je v this.LastValue
        /// </summary>
        protected TKey LastKey;
        /// <summary>
        /// Cache: Výsledek posledního hledání klíče this.LastKey
        /// </summary>
        protected bool LastFound;
        /// <summary>
        /// Cache: Posledně nalezená položka (=data) dle klíče LastKey
        /// </summary>
        protected TValue LastValue;
        /// <summary>
        /// Detekce: hledali jsme posledně danou hodnotu? Neřeším s jakým výsledkem (ten je v this.LastFind, hodnota je v this.LastValue).
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        protected bool LastValueIsForKey(TKey key)
        {
            if (key == null) return false;
            return (this.LastExists && key.Equals(this.LastKey));
        }
        /// <summary>
        /// Detekce: máme v cache nalezenou hodnotu pro hledání daného klíče?
        /// Tzn. posledně jsme hledali tentýž klíč, a data jsme našli. Můžeme vrátit LastValue.
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        protected bool LastValueIsFindForKey(TKey key)
        {
            return (this.LastExists && key.Equals(this.LastKey) && this.LastFound);
        }
        /// <summary>
        /// Cache: uloží si hledaný klíč, výsledek a hodnotu pro příští hledání
        /// </summary>
        /// <param name="key"></param>
        /// <param name="found"></param>
        /// <param name="value"></param>
        protected void LastValueSet(TKey key, bool found, TValue value)
        {
            this.LastExists = true;
            this.LastKey = key;
            this.LastFound = found;
            this.LastValue = value;
        }
        #endregion
        #region Dictionary : přechodníky metod a property z this do this.Dict. Třída this se zvenku tváří jako Dictionary.
        /// <summary>
		/// Initializes a new instance of the System.Collections.Generic.Dictionary«TKey,TValue»
		/// class that is empty, has the default initial capacity, and uses the default
		/// equality comparer for the key type.
        /// </summary>
	    public DictionaryEvnt()
		{
			this.Dict = new Dictionary<TKey,TValue>();
            this.LastValueReset();
		}
        /// <summary>
        /// Initializes a new instance of the System.Collections.Generic.Dictionary«TKey,TValue»
        /// class that contains elements copied from the specified System.Collections.Generic.IDictionary«TKey,TValue»
		/// and uses the default equality comparer for the key type.
        /// </summary>
        /// <exception cref="System.ArgumentNullException">dictionary is null</exception>
        /// <exception cref="System.ArgumentException">dictionary contains one or more duplicate keys.</exception>
        public DictionaryEvnt(IDictionary<TKey, TValue> dictionary)
		{
			this.Dict = new Dictionary<TKey,TValue>(dictionary);
            this.LastValueReset();
        }
        /// <summary>
        /// Initializes a new instance of the System.Collections.Generic.Dictionary«TKey,TValue»
		/// class that is empty, has the default initial capacity, and uses the specified
        /// System.Collections.Generic.IEqualityComparer«T».
        /// </summary>
        /// <param name="comparer">
        /// The System.Collections.Generic.IEqualityComparer«T» implementation to use
        /// when comparing keys, or null to use the default System.Collections.Generic.EqualityComparer«T»
        /// for the type of the key.
        /// </param>
        public DictionaryEvnt(IEqualityComparer<TKey> comparer)
		{
			this.Dict = new Dictionary<TKey, TValue>(comparer);
		}
        /// <summary>
        /// Initializes a new instance of the System.Collections.Generic.Dictionary«TKey,TValue»
		/// class that is empty, has the specified initial capacity, and uses the default
		/// equality comparer for the key type.
        /// </summary>
        /// <param name="capacity">The initial number of elements that the System.Collections.Generic.Dictionary«TKey,TValue» can contain.</param>
        /// <exception cref="System.ArgumentOutOfRangeException">capacity is less than 0.</exception>
        public DictionaryEvnt(int capacity)
		{
			this.Dict = new Dictionary<TKey, TValue>(capacity);
		}
        /// <summary>
        /// Initializes a new instance of the System.Collections.Generic.Dictionary«TKey,TValue»
        /// class that contains elements copied from the specified System.Collections.Generic.IDictionary«TKey,TValue»
		/// and uses the specified System.Collections.Generic.IEqualityComparer«T».
        /// </summary>
        /// <param name="dictionary">The System.Collections.Generic.IDictionary«TKey,TValue» whose elements are copied to the new System.Collections.Generic.Dictionary«TKey,TValue».</param>
        /// <param name="comparer">The System.Collections.Generic.IEqualityComparer«T» implementation to use«T» for the type of the key.</param>
        /// <exception cref="System.ArgumentNullException">dictionary is null.</exception>
        /// <exception cref="System.ArgumentException">dictionary contains one or more duplicate keys.</exception>
        public DictionaryEvnt(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer)
		{
			this.Dict = new Dictionary<TKey, TValue>(dictionary, comparer);
		}
        /// <summary>
        /// Initializes a new instance of the System.Collections.Generic.Dictionary«TKey,TValue»
		/// class that is empty, has the specified initial capacity, and uses the specified
        /// System.Collections.Generic.IEqualityComparer«T».
        /// </summary>
        /// <param name="capacity">The initial number of elements that the System.Collections.Generic.Dictionary«TKey,TValue» can contain.</param>
        /// <param name="comparer">The System.Collections.Generic.IEqualityComparer«T» implementation to use when comparing keys, or null to use the default System.Collections.Generic.EqualityComparer«T» for the type of the key.</param>
        /// <exception cref="System.ArgumentOutOfRangeException">capacity is less than 0.</exception>
        public DictionaryEvnt(int capacity, IEqualityComparer<TKey> comparer)
		{
			this.Dict = new Dictionary<TKey, TValue>(comparer);
		}
        /// <summary>
        /// Gets the System.Collections.Generic.IEqualityComparer«T» that is used to determine equality of keys for the dictionary.
		/// Returns:
        ///     The System.Collections.Generic.IEqualityComparer«T» generic interface implementation
        ///     that is used to determine equality of keys for the current System.Collections.Generic.Dictionary«TKey,TValue»
		///     and to provide hash values for the keys.
        /// </summary>
        public IEqualityComparer<TKey> Comparer
		{ get { return this.Dict.Comparer; } }
        /// <summary>
        /// Gets the number of key/value pairs contained in the System.Collections.Generic.Dictionary«TKey,TValue».
		/// Returns: The number of key/value pairs contained in the System.Collections.Generic.Dictionary«TKey,TValue».
        /// </summary>
        public int Count 
		{ get { return this.Dict.Count; } }
        /// <summary>
        /// Gets a collection containing the keys in the System.Collections.Generic.Dictionary«TKey,TValue».
		/// Returns:
        ///     A System.Collections.Generic.Dictionary«TKey,TValue».KeyCollection containing
        ///     the keys in the System.Collections.Generic.Dictionary«TKey,TValue».
        /// </summary>
        public Dictionary<TKey, TValue>.KeyCollection Keys
		{ get { return this.Dict.Keys; } }
        /// <summary>
        /// Gets a collection containing the values in the System.Collections.Generic.Dictionary«TKey,TValue».
		/// Returns: A System.Collections.Generic.Dictionary«TKey,TValue».ValueCollection containing
        ///     the values in the System.Collections.Generic.Dictionary«TKey,TValue».
        /// </summary>
        public Dictionary<TKey, TValue>.ValueCollection Values
		{ get { return this.Dict.Values; } }
        /// <summary>
        /// Gets or sets the value associated with the specified key.
        /// </summary>
        /// <param name="key">The key of the value to get or set.</param>
        /// <returns>
        /// The value associated with the specified key. If the specified key is not
        /// found, a get operation throws a System.Collections.Generic.KeyNotFoundException,
        /// and a set operation creates a new element with the specified key.
        /// </returns>
        /// <exception cref="System.ArgumentNullException">key is null</exception>
        /// <exception cref="System.Collections.Generic.KeyNotFoundException">The property is retrieved and key does not exist in the collection.</exception>
        public TValue this[TKey key]
		{ 
			get
            {
                if (this.LastValueIsForKey(key))
                {   // Cache:
                    if (this.LastFound) return this.LastValue;
                    // Chyba:
                    throw new FrxException("Key " + key.ToString() + " not found in DictionaryEvnt.");
                }
                TValue value;
                bool found = this.Dict.TryGetValue(key, out value);
                this.LastValueSet(key, found, value);
                if (found) return value;
                throw new FrxException("Key " + key.ToString() + " not found in DictionaryEvnt.");
            }
			set
            {
                this.Dict[key] = value;
                this.LastValueReset();
            }
		}
        /// <summary>
        /// Adds the specified key and value to the dictionary.
        /// </summary>
        /// <param name="key">The key of the element to add.</param>
        /// <param name="value">The value of the element to add. The value can be null for reference types.</param>
        /// <exception cref="System.ArgumentNullException">key is null.</exception>
        /// <exception cref="System.ArgumentException">An element with the same key already exists in the System.Collections.Generic.Dictionary«TKey,TValue»</exception>
        public void Add(TKey key, TValue value)
		{
            bool correct = this.OnItemAdd(key, value);
            if (!correct) return;

            this.Dict.Add(key, value);

            if (this.LastValueIsForKey(key))
                this.LastValueReset();
        }
        /// <summary>
		/// Removes all keys and values from the System.Collections.Generic.Dictionary«TKey,TValue».
        /// </summary>
        public void Clear()
		{
			this.Dict.Clear();
            this.LastValueReset();
		}
        /// <summary>
        /// Determines whether the System.Collections.Generic.Dictionary«TKey,TValue» contains the specified key.
        /// </summary>
        /// <param name="key">The key to locate in the System.Collections.Generic.Dictionary«TKey,TValue»</param>
        /// <returns>true if the System.Collections.Generic.Dictionary«TKey,TValue» contains an element with the specified key; otherwise, false.</returns>
        /// <exception cref="System.ArgumentNullException">key is null</exception>
        public bool ContainsKey(TKey key)
		{
            if (this.LastValueIsForKey(key))
            {   // Cache:
                return this.LastFound;
            }
            TValue value;
            bool found = this.Dict.TryGetValue(key, out value);
            this.LastValueSet(key, found, value);
            return found;
		}
        /// <summary>
        /// Determines whether the System.Collections.Generic.Dictionary«TKey,TValue» contains a specific value.
        /// </summary>
        /// <param name="value">The value to locate in the System.Collections.Generic.Dictionary«TKey,TValue». The value can be null for reference types.</param>
        /// <returns>true if the System.Collections.Generic.Dictionary«TKey,TValue» contains an element with the specified value; otherwise, false.</returns>
        public bool ContainsValue(TValue value)
		{
			return this.Dict.ContainsValue(value);
		}
        /// <summary>
        /// Returns an enumerator that iterates through the System.Collections.Generic.Dictionary«TKey,TValue».
		/// </summary>
        /// <returns>A System.Collections.Generic.Dictionary«TKey,TValue».Enumerator structure for the System.Collections.Generic.Dictionary«TKey,TValue».</returns>
        public Dictionary<TKey, TValue>.Enumerator GetEnumerator()
		{
			return this.Dict.GetEnumerator();
		}
        /// <summary>
        /// Implements the System.Runtime.Serialization.ISerializable interface and returns
		/// the data needed to serialize the System.Collections.Generic.Dictionary«TKey,TValue» instance.
        /// </summary>
        /// <param name="info">
        /// A System.Runtime.Serialization.SerializationInfo object that contains the
        /// information required to serialize the System.Collections.Generic.Dictionary«TKey,TValue»
        /// instance.
        /// </param>
        /// <param name="context">
        /// A System.Runtime.Serialization.StreamingContext structure that contains the
        /// source and destination of the serialized stream associated with the System.Collections.Generic.Dictionary«TKey,TValue»
        /// instance.
        /// </param>
        /// <exception cref="System.ArgumentNullException">info is null</exception>
        [SecurityCritical]
		public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
		{
			this.Dict.GetObjectData(info, context);
		}
        /// <summary>
        /// Implements the System.Runtime.Serialization.ISerializable interface and raises
		/// the deserialization event when the deserialization is complete.
        /// </summary>
        /// <param name="sender">The source of the deserialization event</param>
        /// <exception cref="System.Runtime.Serialization.SerializationException">
        /// The System.Runtime.Serialization.SerializationInfo object associated with
        /// the current System.Collections.Generic.Dictionary«TKey,TValue» instance is
        /// invalid.
        /// </exception>
        public virtual void OnDeserialization(object sender)
		{ }
        /// <summary>
        /// Removes the value with the specified key from the System.Collections.Generic.Dictionary«TKey,TValue».
        /// </summary>
        /// <param name="key">The key of the element to remove.</param>
        /// <returns>
        /// true if the element is successfully found and removed; otherwise, false.
        /// This method returns false if key is not found in the System.Collections.Generic.Dictionary«TKey,TValue».
        /// </returns>
        /// <exception cref="System.ArgumentNullException">key is null</exception>
        public bool Remove(TKey key)
		{
            if (this.LastValueIsForKey(key))
                this.LastValueReset();
            
            return this.Dict.Remove(key);
		}
        /// <summary>
        /// Gets the value associated with the specified key.
        /// </summary>
        /// <param name="key">The key of the value to get.</param>
        /// <param name="value">
        /// When this method returns, contains the value associated with the specified
        /// key, if the key is found; otherwise, the default value for the type of the
        /// value parameter. This parameter is passed uninitialized.
        /// </param>
        /// <returns></returns>
        /// <exception cref="System.ArgumentNullException">key is null</exception>
        public bool TryGetValue(TKey key, out TValue value)
		{
            if (this.LastValueIsForKey(key))
            {   // Cache:
                value = this.LastValue;
                return this.LastFound;
            }
            bool found = this.Dict.TryGetValue(key, out value);
            this.LastValueSet(key, found, value);
            return found;
		}
		#endregion
        #region Protected metody, vyvolávače eventů
        /// <summary>
        /// Vyvolá event ItemAddBefore
        /// </summary>
        protected virtual bool OnItemAdd(TKey key, TValue value)
        {
            bool result = true;
            if (this.ItemAddBefore != null)
            {
                DictionaryEventArgs args = new DictionaryEventArgs(key, value);
                this.ItemAddBefore(this, args);
                result = !args.Cancel;
            }
            return result;
        }
        /// <summary>
        /// Vyvolá event ItemGetBefore
        /// </summary>
        protected virtual void OnItemGet(TKey key, TValue value)
        {
            if (this.ItemGetBefore != null)
                this.ItemGetBefore(this, new DictionaryEventArgs(key, value));
        }
        /// <summary>
        /// Vyvolá event ItemSetBefore
        /// </summary>
        protected virtual void OnItemSet(TKey key, TValue value)
        {
            if (this.ItemSetBefore != null)
                this.ItemSetBefore(this, new DictionaryEventArgs(key, value));
        }
        /// <summary>
        /// Vyvolá event ItemRemoveBefore
        /// </summary>
        protected virtual void OnItemRemove(TKey key, TValue value)
        {
            if (this.ItemRemoveBefore != null)
                this.ItemRemoveBefore(this, new DictionaryEventArgs(key, value));
        }
        #endregion
		#region IEnumerable, IEnumerable<TValue> Members Members
		IEnumerator IEnumerable.GetEnumerator()
		{
			return this.Dict.Values.GetEnumerator();
		}
		IEnumerator<TValue> IEnumerable<TValue>.GetEnumerator()
		{
			return this.Dict.Values.GetEnumerator();
		}
		#endregion
	}
	#endregion
}
